package cn.smile.controller;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
public class TestController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private Redisson redisson;

    /**
     * 使用redis实现分布式锁
     *
     * @return
     */
    @RequestMapping("/test")
    public Object test() throws Exception {
        final String lockKey = "lock";
        final String uuid = UUID.randomUUID().toString().toUpperCase();
        //尝试加锁
        final boolean lock = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, uuid, 10, TimeUnit.SECONDS);
        if (lock) {
            final int goodsCount = Integer.valueOf(stringRedisTemplate.opsForValue().get("goods"));
            if (goodsCount > 0) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (true){
                            try {
                                //每三秒给锁续命一次
                                Thread.sleep(3000);
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                            //续命前判断锁是否存在，以及是否是自己的，如果锁是自己的，则给锁继续续命十秒
                            if (stringRedisTemplate.hasKey(lockKey) && uuid.equals(stringRedisTemplate.opsForValue().get(lockKey))){
                                stringRedisTemplate.expire(lockKey, 10, TimeUnit.SECONDS);
                                System.out.println("续命中...");
                            }else {
                                break;
                            }
                        }
                    }
                }).start();
                final Long goods = stringRedisTemplate.opsForValue().decrement("goods");
                //模拟业务延迟
                Thread.sleep(11000);
                //开锁
                openLock(lockKey,uuid);
                System.out.println("剩余库存：" + goods);
                return "当前库存：" + goods;
            } else {
                //开锁
                openLock(lockKey,uuid);
                System.out.println("已售罄");
                return "已售罄";
            }
        } else {
            System.out.println("未拿到锁");
            return "未拿到锁";
        }
    }

    //释放锁
    private void openLock(String lockKey, String uuid) {
        //将redis中的key查找出来
        final String lockUUID = stringRedisTemplate.opsForValue().get(lockKey);
        if (uuid.equals(lockUUID)) {
            //如果生成的uuid与redis中的uuid相等，直接删除key
            stringRedisTemplate.delete(lockKey);
        }
    }


    /**
     * 使用Redisson实现分布式锁
     */
    @RequestMapping("/test1")
    public Object test1() throws Exception {
        final RLock redissonLock = redisson.getLock("lock_key");
        //尝试加锁，加锁成功为true，否则为false。如果当前逻辑块没有在10秒内完成，则将锁延时
        final boolean tryLock = redissonLock.tryLock(10, TimeUnit.SECONDS);
        if (tryLock) {
            //拿到锁后查询库存
            final int goods = Integer.valueOf(stringRedisTemplate.opsForValue().get("goods"));
            if (goods > 0) {
                //得到锁后就开始将库存减1
                final Long goods1 = stringRedisTemplate.opsForValue().decrement("goods");
                System.out.println("库存：" + goods1);
                //解锁，将锁释放
                redissonLock.unlock();
                return "当前库存：" + goods1;
            } else {
                System.out.println("已售罄");
                //解锁，将锁释放
                redissonLock.unlock();
                return "已售罄";
            }
        } else {
            System.out.println("没有拿到锁");
            return "服务繁忙！";
        }
    }


}